#include <stdexcept>

#include "JpgEncoder.hpp"
#include "util/debug.h"

JpgEncoder::JpgEncoder(unsigned int prePadding, unsigned int postPadding)
  : mTjHandle(tjInitCompress()),
    mSubsampling(TJSAMP_420),
    mEncodedData(NULL),
    mPrePadding(prePadding),
    mPostPadding(postPadding),
    mMaxWidth(0),
    mMaxHeight(0)
{
}

JpgEncoder::~JpgEncoder() {
  tjFree(mEncodedData);
}

bool JpgEncoder::release() {
  if (mEncodedData != NULL) {
    tjFree(mEncodedData);
    mEncodedData = NULL;
  }

  mMaxHeight = 0;
  mMaxWidth = 0;
}

bool
JpgEncoder::encode(Minicap::Frame* frame, unsigned int quality) {
  unsigned char* offset = getEncodedData();
   


  //print_debug_info(__FILE__, __LINE__, __FUNCTION__, "encode %d %d %d %d %d!!!!!!!!!!!!!!!!!!!!!!!!!\n", 
	 // frame->width,
	 // frame->stride * frame->bpp,
	 // frame->height,
	 // convertFormat(frame->format),
	 // mSubsampling
	 // );

  return 0 == tjCompress2(
    mTjHandle,
    (unsigned char*) frame->data,
    frame->width,
    frame->stride * frame->bpp,
    frame->height,
    convertFormat(frame->format),
    &offset,
    &mEncodedSize,
    mSubsampling,
    quality,
    TJFLAG_FASTDCT | TJFLAG_NOREALLOC
  );
}

int trgb2yuv(unsigned char* rgb_buffer, int width, int height, unsigned char** yuv_buffer, int * yuv_size, int subsample)
{
	tjhandle handle = NULL;
	int flags = 0;
	int padding = 1; // 1��4���ɣ���������0
	int pixelfmt = TJPF_RGBA;
	int ret = 0;

  print_debug_info(__FILE__, __LINE__, __FUNCTION__, "------------%dx%d------------\r\n", width, height);

	handle = tjInitCompress();

	flags |= 0;

	*yuv_size = tjBufSizeYUV2(width, padding, height, subsample);

	if (*yuv_buffer == NULL)
	{
		*yuv_buffer = (unsigned char *)malloc(*yuv_size);
		print_debug_info(__FILE__, __LINE__, __FUNCTION__, "tjBufSizeYUV2  *yuv_size %d %d %d\n", width, height, *yuv_size);

	}

	if (*yuv_buffer == NULL)
	{
		print_debug_info(__FILE__, __LINE__, __FUNCTION__, "malloc buffer for rgb failed.\n");
		return -1;
	}
	ret = tjEncodeYUV3(handle, rgb_buffer, width, 0, height, pixelfmt, *yuv_buffer, padding, subsample, flags);
	if (ret < 0)
	{
		print_debug_info(__FILE__, __LINE__, __FUNCTION__, "encode to yuv failed: %s\n", tjGetErrorStr());
	}

	tjDestroy(handle);

	return ret;
}

 
bool
JpgEncoder::encodeYuv(Minicap::Frame* frame, unsigned int quality, unsigned char* yuv_buffer, int * yuv_size) 
{
	unsigned char* offset = getEncodedData();


	//trgb2yuv(rgb_buffer, width, height, &yuv_buffer, &yuv_size, subsample);

	trgb2yuv((unsigned char*)frame->data,
		frame->width,
		frame->height, 
		&yuv_buffer,
		yuv_size,
		mSubsampling);

	//print_debug_info(__FILE__, __LINE__, __FUNCTION__, "trgb2yuv %p  %d \n", yuv_buffer,*yuv_size);


	return 0;
}


int
JpgEncoder::getEncodedSize() {
  return mEncodedSize;
}

unsigned char*
JpgEncoder::getEncodedData() {
  return mEncodedData + mPrePadding;
}

bool
JpgEncoder::reserveData(uint32_t width, uint32_t height) {
  MCINFO("reserveData: %dx%d@%dx%d", width, height, mMaxWidth, mMaxHeight);
  if (width == mMaxWidth && height == mMaxHeight) {
    return 0;
  }

  tjFree(mEncodedData);

  unsigned long maxSize = mPrePadding + mPostPadding + tjBufSize(
    width,
    height,
    mSubsampling
  );

  MCINFO("Allocating %ld bytes for JPG encoder", maxSize);

  mEncodedData = tjAlloc(maxSize);

  if (mEncodedData == NULL) {
    return false;
  }

  mMaxWidth = width;
  mMaxHeight = height;

  return true;
}

int
JpgEncoder::convertFormat(Minicap::Format format) {
  switch (format) {
  case Minicap::FORMAT_RGBA_8888:
    return TJPF_RGBA;
  case Minicap::FORMAT_RGBX_8888:
    return TJPF_RGBX;
  case Minicap::FORMAT_RGB_888:
    return TJPF_RGB;
  case Minicap::FORMAT_BGRA_8888:
    return TJPF_BGRA;
  default:
    throw std::runtime_error("Unsupported pixel format");
  }
}
